package scala.examples.fs.syntax;

object Syntax {
  trait Term {
        // @result == true || @result == false
  	def isPath = false
  }
  
  trait Path extends Term {override def isPath = true}

  case class Name(n: String) extends Path
  object Binder {
    def make[VarT, ScopeT](scope: ScopeT, boundVar: VarT): Binder[VarT, ScopeT] = null
  }
  trait Binder[VarT, ScopeT] {
    def apply(varValue: VarT): ScopeT                                                    
  }
  
  case class FieldAccess(tgt: Term, label: String) extends Term /*with Path if(e.isInstanceOf[Path])*/ {
    override def isPath = tgt.isPath 
  }
  
  case class MethodCall(tgt: Term, label: String, args: List[Term]) extends Term 

  case class New(tp: Type) extends Path
  case class LocalVal(tp: Type, value :Term, scope: Binder[Path, Term]) extends Term

  case object Unit extends Term with Path

  trait Type;
    case class TypeSelect(t: Type, label: String) extends Type
    case class Single(e: Term) extends Type
    case class Signature(sig: Binder[Path, List[Member]]) extends Type

  case class Member(label: String) {
    def corresponds(other: Member): Boolean = this.label equals other.label 
  }
  
  trait Declaration extends Member
  trait Definition extends Member

  case class ValSig(l: String, t: Type, e: Option[Term]) extends Member(l) // huh, can inherit from case class now?
  class ValDcl(l: String, t: Type) extends ValSig(l, t, None) with Declaration 
  class ValDef(l: String, t: Type, e: Term) extends ValSig(l, t, Some(e)) with Definition

  case class Arg(name: String, typ: Type)

  case class DefSig(l: String, args :List[Arg], t: Type, body: Option[Term]) extends Member(l)
  class DefDcl(l: String, args :List[Arg], t: Type)  extends DefSig(l, args, t, None) with Declaration 
  class DefDef(l: String, args :List[Arg], t: Type, body: Term) extends DefSig(l, args, t, Some(body)) with  Definition

  case class TypeSig(l: String, t: Option[Type]) extends Member(l)
  class TypeDcl(l: String) extends TypeSig(l, None) with Declaration 
  class TypeDef(l: String, t: Type) extends TypeSig(l, Some(t)) with Definition

}


/*trait Member {
    type BoundEntity // the "value" "stored" in this member
    type ClassifyingEntity // the "type" classifying the "value" bound by this member
    def label: String
    def boundEntity: Option[BoundEntity]
    def classifyingEntity: Option[ClassifyingEntity]
    def corresponds(other: Member): Boolean = this.label equals other.label 
  }
  
  trait Declaration extends Member
  trait Definition extends Member

  case class ValSig(l: String, t: Type, e: Option[Term]) extends Member {type BoundEntity=Term; type ClassifyingEntity=Type; def label=l; def boundEntity=e; def classifyingEntity=t}
  class ValDcl(l: String, t: Type) extends ValSig(l, t, None) with Declaration 
  class ValDef(l: String, t: Type, e: Term) extends ValSig(l, t, Some(e)) with Definition

  case class Arg(name: String, typ: Type)

  case class Method(args :List[Arg], body: Option[Term])
  case class DefSig(l: String, args :List[Arg], t: Type, body: Option[Term]) extends Member {type BoundEntity=Method; type ClassifyingEntity=Type; def label = l; def boundEntity=Method(args, body); def classifyingEntity=t }
  class DefDcl(l: String, args :List[Arg], t: Type)  extends DefSig(l, args, t, None) with Declaration 
  class DefDef(l: String, args :List[Arg], t: Type, body: Term) extends DefSig(l, args, t, Some(body)) with  Definition

  case class TypeSig(l: String, t: Option[Type]) extends Member with Declaration { def label = l }  
  case class TypeDcl(l: String) extends TypeSig(l, None) with Declaration 
  case class TypeDef(l: String, t: Type) extends TypeSig(l, Some(t)) with Definition*/